package functionroots.primitives;

/**
 * Provides an abstraction for real, single-variable functions which are
 * continuous over certain real intervals. Only simple intervals in the forms
 * [a, b] ]a, b[ ]a, b] and [a, b[ and unions of such are supported. Periodic
 * intervals as the tangent function has are yet to be implemented.
 * @author orion
 */
//TODO: Completar instanciação de modelos de funções elementares que estão faltando (c, a^x, x^a, x^x, senh, cosh, tgh, sec, cossec, cotg, acos, asen, atg, acosh, asenh, atgh).
public interface RealFunction {

    public static final RealFunction absolute = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.abs(x);
        }

        @Override
        public String text(double x) {
            return "|" + x + "|";
        }
    };
    public static final RealFunction base10Logarithm = new RealFunction() {

        @Override
        public double value(double x) {
            if (x <= 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.log10(x);
            }
        }

        @Override
        public String text(double x) {
            return "log10(" + x + ")";
        }
    };
    public static final RealFunction cubeRoot = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.cbrt(x);
        }

        @Override
        public String text(double x) {
            return "cbrt(" + x + ")";
        }
    };
    public static final RealFunction cossine = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.cos(x);
        }

        @Override
        public String text(double x) {
            return "cos(" + x + ")";
        }
    };
    public static final RealFunction exponential = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.exp(x);
        }

        @Override
        public String text(double x) {
            return "exp(" + x + ")";
        }
    };
    public static final RealFunction logarithm = new RealFunction() {

        @Override
        public double value(double x) {
            if (x <= 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.log(x);
            }
        }

        @Override
        public String text(double x) {
            return "1/" + x;
        }
    };
    public static final RealFunction sine = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.sin(x);
        }

        @Override
        public String text(double x) {
            return "sin(" + x + ")";
        }
    };
    public static final RealFunction squareRoot = new RealFunction() {

        @Override
        public double value(double x) {
            if (x < 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.sqrt(x);
            }
        }

        @Override
        public String text(double x) {
            return "sqrt(" + x + ")";
        }
    };
    public static final RealFunction tangent = new RealFunction() {

        @Override
        public double value(double x) {
            return Math.tan(x);
        }

        @Override
        public String text(double x) {
            return "tan(" + x + ")";
        }
    };

    /**
     * Provides the calculation of the proposed function single-variable.
     * @param x The proposed function's argument.
     * @return The value of the implemented function on the given argument.
     * @throws IllegalArgumentException if the given argument does no belong to
     * the function's domain.
     */
    public double value(double x);

    public String text(double x);
}
